﻿using System;
using System.Text;
using System.Net;
using System.Net.Security;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Specialized;

namespace _12306Bot.Common
{
    public class WebBot
    {
        //private HttpWebRequest request;

        //代理服务器
        private WebProxy proxy;

        /// <summary>
        /// 链接的前面共通部分
        /// </summary>
        public Uri uriBase;

        /// <summary>
        /// 服务器时间
        /// </summary>
        private DateTime _dteServer;
        /// <summary>
        /// 服务器时间
        /// </summary>
        public DateTime DteServer
        {
            get { return _dteServer; }
        }

        /// <summary>
        /// 是否使用默认代理
        /// </summary>
        private Boolean IsUseDefaultProxy = false;
        

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        /// <param name="strProxyAddr">代理服务器地址</param>
        /// <param name="iProxyPort">代理服务器端口</param>
        /// <param name="strProxyUsername">代理服务器用户名</param>
        /// <param name="strProxyPassword">代理服务器密码</param>
        /// <param name="strProxyPassword">是否使用默认代理</param>
        public WebBot(String strProxyAddr, String strProxyPort, String strProxyUsername, String strProxyPassword, Boolean IsUseDefaultProxy)
            : this()
        {
            if (strProxyAddr != "" && strProxyPort != "")
            {
                proxy = new WebProxy(strProxyAddr, Convert.ToInt32(strProxyPort));
                proxy.Credentials = new NetworkCredential(strProxyUsername, strProxyPassword);
            }

            this.IsUseDefaultProxy = IsUseDefaultProxy;
        }

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public WebBot()
        {
            uriBase = new Uri("https://dynamic.12306.cn/");
        }

        /// <summary>
        /// 发送数据到服务器
        /// <para>Get模式</para>
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="cookconReq"></param>
        /// <returns></returns>
        public HttpWebResponse SendData(HttpWebRequest request, ref CookieContainer cookconReq)
        {
            return SendData(request, "", ref cookconReq);
        }

        /// <summary>
        /// 发送数据到服务器
        /// <para>Get模式，无需Cookie</para>
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public HttpWebResponse SendData(HttpWebRequest request)
        {
            CookieContainer cc = new CookieContainer();
            return SendData(request, ref cc);
        }

        //发送数据到服务器
        public HttpWebResponse SendData(HttpWebRequest request, String strPostData, ref CookieContainer cookconReq)
        {
            try
            {
                //证书无条件确认
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(RemoteCertificateValidationCallback);

                //禁止自动页面跳转
                request.AllowAutoRedirect = false;

                //给Request设置代理服务器
                if (this.IsUseDefaultProxy)
                {
                    request.UseDefaultCredentials = true;
                }
                else if (proxy != null)
                {
                    request.Proxy = proxy;
                }

                //设置Cookie
                if (cookconReq.Count == 0)
                {
                    request.CookieContainer = new CookieContainer();
                    cookconReq = request.CookieContainer;
                }
                else
                {
                    request.CookieContainer = cookconReq;
                }

                request.Headers["Accept-Language"] = "zh-CN,zh;q=0.5";
                request.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
                request.Headers["Accept-Encoding"] = "gzip";
                request.KeepAlive = true;
                //设置解压模式，设置了gzip, deflate后就要设置下面这条
                request.AutomaticDecompression = DecompressionMethods.Deflate;

                //这段要放在下面，否则上面的设置会有问题
                if (strPostData.Equals(""))
                {
                    request.Method = "GET";
                }
                else
                {
                    request.Method = "POST";

                    request.ServicePoint.Expect100Continue = false;

                    byte[] btsPostData = Encoding.ASCII.GetBytes(strPostData);
                    request.ContentLength = btsPostData.Length;
                    //写入数据到流
                    using (Stream strmReq = request.GetRequestStream())
                    {
                        strmReq.Write(btsPostData, 0, btsPostData.Length);
                        strmReq.Close();
                        strmReq.Dispose();
                    }
                }

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                //页面出错，抛出错误
                if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Found)
                {
                    Exception exWeb = new Exception();
                    exWeb.Data.Add("HttpStatusError", response.StatusCode);
                    throw exWeb;
                }
                //得到服务器时间
                _dteServer = Convert.ToDateTime(response.Headers["Date"]);

                return response;
            }
            catch (WebException wex)
            {
                Exception ex = new Exception(wex.Message);
                throw ex;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //证书确认方法
        private bool RemoteCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            //Return True to force the certificate to be accepted.
            return true;
        }

        /// <summary>
        /// 读取流到字符串
        /// </summary>
        /// <param name="respRtn">数据流</param>
        /// <returns>转换的字符串</returns>
        public String ReadStream(HttpWebResponse respRtn)
        {
            Stream strmRtn = respRtn.GetResponseStream();
            StreamReader strmRder;
            if (respRtn.Headers["Content-Encoding"] == "gzip")
            {
                GZipStream dstrmResp = new GZipStream(strmRtn, CompressionMode.Decompress);
                strmRder = new StreamReader(dstrmResp, Encoding.UTF8);
            }
            else
            {
                strmRder = new StreamReader(strmRtn, Encoding.UTF8);
            }
            string strRtn = strmRder.ReadToEnd();
            strmRder.Close();
            strmRtn.Close();
            respRtn.Close();
            //TODO不知道下面这行为什么要添加
            //request.KeepAlive = false;
            return strRtn;
        }

        //出错处理
        public String strProcessError(Exception ex)
        {
            if (ex.Data.Contains("HttpStatusError"))
            {
                return "网站忙，连接失败！";
            }
            else
            {
                return ex.Message;
            }
        }

        public void SetHeaderValue(WebHeaderCollection header, string name, string value)
        {
            var property = typeof(WebHeaderCollection).GetProperty("InnerCollection",
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (property != null)
            {
                var collection = property.GetValue(header, null) as NameValueCollection;
                collection[name] = value;
            }
        }
    }
}